
import java.util.*;

/**
 * <p>
 * Controlador do Sistema de Elevadores.
 * </p>
 */
class Controlador implements IControlador {

  ///////////////////////////////////////
  // attributes


/**
 * <p>
 * Representa o numero de andares do Predio antendidos pelo Elevador e
 * enumerados de 1 a numAndares.
 * </p>
 */
    private int numAndares; 

/**
 * <p>
 * Representa o tempo entre a abertura e o fechamento da Porta do Elevador.
 * </p>
 */
    public static final int aberturaPorta = 2500; 

/**
 * <p>
 * Representa o tempo necessario para o Elevador se deslocar de uma andar
 * para um andar adjacente.
 * </p>
 */
    public static final int deslocamentoAndar = 2000; 

/**
 * <p>
 * Representa movimento para cima.
 * </p>
 */
    public static final int paraCima = 1; 

/**
 * <p>
 * Representa ausencia de movimento.
 * </p>
 */
    public static final int parado = 0; 

/**
 * <p>
 * Representa movimento para baixo.
 * </p>
 */
    public static final int paraBaixo = -1; 

   ///////////////////////////////////////
   // associations

/**
 * <p>
 * Elevador subordinado ao Controlador.
 * </p>
 */
    protected Elevador elevador; 
/**
 * 
 */
    protected IInterfaceDeUsuario iInterfaceDeUsuario; 
/**
 * <p>
 * Representa uma colecao de instancias de BotaoDeRequisicao. Uma instancia
 * e' instalada em cada andar, exceto no primeiro, e indica a intencao do
 * Passgeiro em se deslocar para baixo.
 * </p>
 */
    protected ArrayList<BotaoDeRequisicao> botaoDescida = new ArrayList<BotaoDeRequisicao>();
/**
 * <p>
 * Representa uma colecao de instancias de BotaoDeRequisicao. Uma instancia
 * e' instalada em cada andar, exceto no ultimo, e indica a intencao do
 * Passgeiro em se deslocar para cima.
 * </p>
 */
    protected ArrayList<BotaoDeRequisicao> botaoSubida = new ArrayList<BotaoDeRequisicao>();


  ///////////////////////////////////////
  // operations


/**
 * <p>
 * Gera uma instancia de Controlador.
 * </p>
 * 
 * @return <p>
 * Retorna uma instancia de Controlador.
 * </p>
 * 
 * @param numAndares <p>
 * Representa o numero de andares do Predio atendidos pelo Elevador. Os
 * andares sao enumerados de 1 a numAndares.
 * </p>
 * 
 * @param posicaoInicialDoElevador 
 * @param portaInicialmenteFechada 
 */
    public  Controlador(int numAndares, int posicaoInicialDoElevador, boolean portaInicialmenteFechada) {        
        int andar;
        this.numAndares = numAndares;
        elevador = new Elevador(this, 1, numAndares, posicaoInicialDoElevador, portaInicialmenteFechada);
        elevador.start();
        botaoDescida.ensureCapacity(numAndares + 1);
        botaoDescida.add(0, null);
        botaoDescida.add(1, null);
        for (andar = 2; andar <= numAndares; andar++)
            botaoDescida.add(andar, new BotaoDeRequisicao(andar, paraBaixo, this));
        botaoSubida.ensureCapacity(numAndares + 1);
        botaoSubida.add(0, null);
        for (andar = 1; andar < numAndares; andar++)
            botaoSubida.add(andar,new BotaoDeRequisicao(andar, paraCima, this));
    } // end Controlador        

/**
 * <p>
 * Retorna botaoSubida associado a andar.
 * </p>
 * 
 * @return um BotaoDeRequisicao.
 * 
 * @param andar - andar onde se encontra instalado o botaoSubida.
 */
    private BotaoDeRequisicao getBotaoSubida(int andar) {        
        return botaoSubida.get(andar);
    } // end getBotaoSubida        

/**
 * <p>
 * Retorna botaoDescida associado a andar.
 * </p>
 * 
 * @return um BotaoDeRequisicao.
 * 
 * @param andar - andar onde se encontra instalado o botaoDescida.
 */
    private BotaoDeRequisicao getBotaoDescida(int andar) {        
        return botaoDescida.get(andar);
    } // end getBotaoDescida        

/**
 * <p>
 * Informa ao Elevador que ha' uma solicitacao no andarDesejado.
 * </p>
 * 
 * @param andarDesejado <p>
 * andarDesejado - andar em que foi acionado um BotaoDeSelecao.
 * </p>
 * 
 * - andar em que foi acionado um BotaoDeRequisicao.
 */
    public void solicitarElevador(int andarDesejado) {        
        elevador.moverPara(andarDesejado);
    } // end solicitarElevador        

/**
 * <p>
 * Verifica se o BotaoSubida em andar esta' armado.
 * </p>
 * 
 * @return true se o BotaoSubida em andar esta' armado.
 * 
 * @param andar - andar associado ao BotaoSubida a ser verificado.
 */
    public synchronized boolean isArmadoBotaoSubida(int andar) {        
        if (andar < numAndares) return getBotaoSubida(andar).isArmado();
        else return false;
    } // end isArmadoBotaoSubida        

/**
 * <p>
 * Verifica se o BotaoDescida em andar esta' armado.
 * </p>
 * 
 * @return true se o BotaoDescida em andar esta' armado.
 * 
 * @param andar - andar associado ao BotaoDescida a ser verificado.
 */
    public synchronized boolean isArmadoBotaoDescida(int andar) {        
        if (andar > 1) return getBotaoDescida(andar).isArmado();
        else return false;
    } // end isArmadoBotaoDescida        

/**
 * <p>
 * Notifica BotaoSubida de andar que chegou o Elevador.
 * </p>
 * 
 * @param andar - andar em que acaba de chegar o Elevador.
 */
    public synchronized void registrarChegadaElevadorBotaoSubida(int andar) {        
        if (andar < numAndares) getBotaoSubida(andar).registrarElevadorNoAndar();
    } // end registrarChegadaElevadorBotaoSubida        

/**
 * <p>
 * Notifica BotaoDescida de andar que chegou o Elevador.
 * </p>
 * 
 * @param andar - andar em que acaba de chegar o Elevador.
 */
    public synchronized void registrarChegadaElevadorBotaoDescida(int andar) {        
        if (andar > 1) getBotaoDescida(andar).registrarElevadorNoAndar();
    } // end registrarChegadaElevadorBotaoDescida        

/**
 * <p>
 * Repassa a informacao de que o BotaoDeSelecao associado ao andar indicado
 * e instalado no Elevador indicado foi acionado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 * @param andar - andar associado ao BotaoDeSelecao acionado.
 */
    public synchronized void registrarBotaoDeSelecaoAcionado(int indElevador, int andar) {        
        elevador.registrarBotaoDeSelecaoAcionado(andar);
    } // end registrarBotaoDeSelecaoAcionado        

/**
 * <p>
 * Repassa a informacao de que o BotaoDeRequisicao que representa a
 * intencao de descer e instalado no andar indicado foi acionado.
 * </p>
 * 
 * @param andar - andar em que se encontra instalado o BotaoDeRequisicao.
 */
    public synchronized void registrarBotaoDescidaAcionado(int andar) {        
        getBotaoDescida(andar).requisitarElevador();
    } // end registrarBotaoDescidaAcionado        

/**
 * <p>
 * Repassa a informacao de que o BotaoDeRequisicao que representa a
 * intencao de subir e instalado no andar indicado foi acionado.
 * </p>
 * 
 * @param andar - andar em que se encontra instalado o BotaoDeRequisicao.
 */
    public synchronized void registrarBotaoSubidaAcionado(int andar) {        
        getBotaoSubida(andar).requisitarElevador();
    } // end registrarBotaoSubidaAcionado        

/**
 * <p>
 * Solicita 'a interface de usuario que indique ao usuario que o
 * BotaoDeRequisicao instalado no andar identificado e representante da
 * intencao de movimento em um particular direcao foi armado.
 * </p>
 * 
 * @param andar - andar onde se encontra instalado o BotaoDeRequisicao.
 * 
 * @param direcao - intencao de movimento representado pelo
 * BotaoDeRequisicao.
 */
    public synchronized void registrarBotaoDeRequisicaoArmado(int andar, int direcao) {        
        if (direcao == paraCima)
            iInterfaceDeUsuario.armarBotaoSubida(andar);
        else iInterfaceDeUsuario.armarBotaoDescida(andar);
    } // end registrarBotaoDeRequisicaoArmado        

/**
 * <p>
 * Solicita 'a interface de usuario que indique ao usuario que o
 * BotaoDeRequisicao instalado no andar identificado e representante da
 * intencao de movimento em um particular direcao foi desarmado.
 * </p>
 * 
 * @param andar - andar onde se encontra instalado o BotaoDeRequisicao.
 * 
 * @param direcao - intencao de movimento representado pelo
 * BotaoDeRequisicao.
 */
    public synchronized void registrarBotaoDeRequisicaoDesarmado(int andar, int direcao) {        
        if (direcao == paraCima)
            iInterfaceDeUsuario.desarmarBotaoSubida(andar);
        else 
        	iInterfaceDeUsuario.desarmarBotaoDescida(andar);
    } // end registrarBotaoDeRequisicaoDesarmado        

/**
 * <p>
 * Solicita que a interface de usuario indique ao usuario que o
 * BotaoDeSelecao associado ao andar identificado e instalado no Elevador
 * apontado foi armado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 * @param andar - andar associado ao BotaoDeSelecao.
 */
    public synchronized void registrarBotaoDeSelecaoArmado(int indElevador, int andar) {        
        iInterfaceDeUsuario.armarBotaoSelecao(indElevador, andar);
    } // end registrarBotaoDeSelecaoArmado        

/**
 * <p>
 * Solicita que a interface de usuario indique ao usuario que o
 * BotaoDeSelecao associado ao andar identificado e instalado no Elevador
 * apontado foi desarmado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 * @param andar - andar associado ao BotaoDeSelecao.
 */
    public synchronized void registrarBotaoDeSelecaoDesarmado(int indElevador, int andar) {        
        iInterfaceDeUsuario.desarmarBotaoSelecao(indElevador, andar);
    } // end registrarBotaoDeSelecaoDesarmado        

/**
 * <p>
 * Recebe a referencia da interface da InterfaceDeUsuario com que vai
 * interagir.
 * </p>
 * 
 * @param iInterfaceDeUsuario - representa a interface de usuario.
 */
    public synchronized void registrarInterfaceDeUsuario(IInterfaceDeUsuario iInterfaceDeUsuario) {        
        this.iInterfaceDeUsuario = iInterfaceDeUsuario;
    } // end registrarInterfaceDeUsuario        

/**
 * <p>
 * Repassa 'a interface de usuario a informacao sobre o estado da Porta do
 * Elevador indicado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 * @param fechada - true se a Porta se encontrar fechada.
 */
    public synchronized void notificarEstadoPorta(int indElevador, boolean fechada) {        
        iInterfaceDeUsuario.registrarEstadoPorta(indElevador, fechada);
    } // end notificarEstadoPorta        

/**
 * <p>
 * Recebe e repassa 'a interface de usuario uma nova posicao de um Elevador.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 * @param andar - andar em que se encontra o Elevador indicado.
 */
    public synchronized void registrarPosicaoElevador(int indElevador, int andar) {        
        iInterfaceDeUsuario.registrarPosicaoElevador(indElevador, andar);
    } // end registrarPosicaoElevador        


/**
 * <p>
 * Solicita que a interface de usuario indique ao usuario que o
 * BotaoDeEmergencia instalado no Elevador
 * apontado foi armado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 */
    public synchronized void registrarBotaoDeEmergenciaArmado(int indElevador) {        
        iInterfaceDeUsuario.armarBotaoDeEmergencia(indElevador);
    } // end registrarBotaoDeEmergenciaArmado        

/**
 * <p>
 * Solicita que a interface de usuario indique ao usuario que o
 * BotaoDeEmergencia associado instalado no Elevador
 * apontado foi desarmado.
 * </p>
 * 
 * @param indElevador - indicador do Elevador envolvido.
 * 
 */
    public synchronized void registrarBotaoDeEmergenciaDesarmado(int indElevador) {        
        iInterfaceDeUsuario.desarmarBotaoDeEmergencia(indElevador);
    } // end registrarBotaoDeEmergenciaDesarmado        


    /**
     * <p>
     * Repassa a informacao de que o BotaoDeEmergencia associado ao Elevador indicado foi acionado.
     * </p>
     * 
     * @param indElevador - indicador do Elevador envolvido.
     */
        public synchronized void registrarBotaoDeEmergenciaAcionado(int indElevador) {        
            elevador.registrarBotaoDeEmergenciaAcionado();
        } // end registrarBotaoDeSelecaoAcionado        
        
        
 } // end Controlador



